package org.dgt.dao;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * @author Alessio Pace link
 * @see http://forum.springsource.org/showthread.php?25160-Adding-GenericDAO-classes-to-Spring
 */
public class PersistenceManagerHibernate extends HibernateDaoSupport implements
		PersistenceManager {

	protected Logger logger = LoggerFactory.getLogger(PersistenceManager.class
			.getName());

	public PersistenceManagerHibernate() {
		super();
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> findAll(Class<T> entityClass) throws DataAccessException {

		// getHibernateTemplate().setCacheQueries(true);
		List<T> results = getHibernateTemplate().loadAll(entityClass);

		Set<T> set = new HashSet<T>(results);
		results = new ArrayList<T>(set);
		return results;
	}

	@SuppressWarnings("unchecked")
	public <T> T findById(Class<T> entityClass, Long id)
			throws DataAccessException {

		// getHibernateTemplate().setCacheQueries(true);
		T o = (T) getHibernateTemplate().get(entityClass, id);
		if (o == null) {
			logger.warn("uh oh, document with id '" + id + "' not found...");
			throw new ObjectRetrievalFailureException(entityClass, id);
		} else {
			return o;
		}
	}

	public <T> void saveOrUpdate(T entity) throws DataAccessException {
		getHibernateTemplate().saveOrUpdate(entity);
	}

	@SuppressWarnings("unchecked")
	public <T> T merge(T entity) throws DataAccessException {
		return (T) getHibernateTemplate().merge(entity);
	}

	public <T> void remove(T entity) throws DataAccessException {
		getHibernateTemplate().delete(entity);
	}

	public <T> void removeAll(Class<T> entityClass) throws DataAccessException {
		getHibernateTemplate().deleteAll(this.findAll(entityClass));
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> findByNamedQueryAndNamedParam(Class<T> entityClass,
			String queryName, String[] paramNames, Object[] values)
			throws DataAccessException {

		List<T> results = (List<T>) getHibernateTemplate()
				.findByNamedQueryAndNamedParam(queryName, paramNames, values);
		return results;
	}

	public <T> List<T> findByNamedQueryAndNamedParam(Class<T> entityClass,
			String queryName, Map<String, ?> params) throws DataAccessException {

		String[] paramNames = new String[params.size()];
		Object[] values = new Object[params.size()];

		List<String> keys = new ArrayList<String>(params.keySet());
		for (int i = 0; i < keys.size(); i++) {
			String k = keys.get(i);
			paramNames[i] = k;
			values[i] = params.get(k);
		}

		return this.findByNamedQueryAndNamedParam(entityClass, queryName,
				paramNames, values);
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> findByNamedParam(Class<T> entityClass, String query,
			String[] paramNames, Object[] values) throws DataAccessException {

		List<T> results = (List<T>) getHibernateTemplate().findByNamedParam(
				query, paramNames, values);
		return results;

	}

	@SuppressWarnings("unchecked")
	public <T> List<T> findByNamedParam(Class<T> entityClass, String query,
			Map<String, ?> params) throws DataAccessException {

		String[] paramNames = new String[params.size()];
		Object[] values = new Object[params.size()];

		List<String> keys = new ArrayList<String>(params.keySet());
		for (int i = 0; i < keys.size(); i++) {
			String k = keys.get(i);
			paramNames[i] = k;
			values[i] = params.get(k);
		}

		List<T> results = (List<T>) getHibernateTemplate().findByNamedParam(
				query, paramNames, values);
		return results;

	}
	
}
